package com.eian.boot.crypto.service;

import com.eian.boot.crypto.core.CryptoService;
import com.eian.boot.crypto.core.DecryptStrategy;
import com.eian.boot.crypto.core.EncryptStrategy;
import com.eian.boot.crypto.enums.CryptoAlgorithm;
import com.eian.boot.crypto.exception.AlgorithmException;
import com.eian.boot.crypto.exception.CryptoException;
import com.eian.boot.crypto.model.CryptoContext;
import com.eian.boot.crypto.model.CryptoResult;
import com.eian.boot.crypto.model.KeyPairInfo;
import com.eian.boot.crypto.store.KeyStore;
import com.eian.boot.crypto.store.NoOpKeyStore;
import com.eian.boot.crypto.utils.KeyUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 默认加密服务实现
 *
 * @author eian
 */
@Slf4j
@Service
public class DefaultCryptoService implements CryptoService {

    /**
     * 加密策略注册表
     */
    private final Map<CryptoAlgorithm, EncryptStrategy> encryptStrategies = new ConcurrentHashMap<>();

    /**
     * 解密策略注册表
     */
    private final Map<CryptoAlgorithm, DecryptStrategy> decryptStrategies = new ConcurrentHashMap<>();

    /**
     * 密钥存储（默认不存储）
     */
    private KeyStore keyStore = new NoOpKeyStore();

    @Override
    public CryptoResult encrypt(String plaintext, CryptoAlgorithm algorithm, CryptoContext context) {
        try {
            EncryptStrategy strategy = encryptStrategies.get(algorithm);
            if (strategy == null) {
                throw new AlgorithmException("未找到算法的加密策略: " + algorithm.name());
            }

            String encrypted = strategy.encrypt(plaintext, context);

            // 构建结果
            CryptoResult.CryptoResultBuilder resultBuilder = CryptoResult.builder()
                    .data(encrypted)
                    .success(true);

            // 如果需要存储密钥
            if (context.isStoreKey()) {
                String keyId = context.getKeyId();
                if (keyId == null || keyId.trim().isEmpty()) {
                    throw new CryptoException("存储密钥时必须提供keyId");
                }

                // 存储密钥上下文
                keyStore.store(keyId, context);
                resultBuilder.keyId(keyId);

                log.debug("Stored encryption key: {}", keyId);
            }

            return resultBuilder.build();
        } catch (Exception e) {
            log.error("加密失败: algorithm={}, error={}", algorithm, e.getMessage(), e);
            return CryptoResult.failure(e.getMessage());
        }
    }

    @Override
    public CryptoResult decrypt(String ciphertext, CryptoAlgorithm algorithm, CryptoContext context) {
        try {
            DecryptStrategy strategy = decryptStrategies.get(algorithm);
            if (strategy == null) {
                throw new AlgorithmException("未找到算法的解密策略: " + algorithm.name());
            }

            String decrypted = strategy.decrypt(ciphertext, context);
            return CryptoResult.success(decrypted);
        } catch (Exception e) {
            log.error("解密失败: algorithm={}, error={}", algorithm, e.getMessage(), e);
            return CryptoResult.failure(e.getMessage());
        }
    }

    @Override
    public String generateSymmetricKey(CryptoAlgorithm algorithm, int keySize) {
        if (!algorithm.isSymmetric()) {
            throw new AlgorithmException("算法不是对称加密算法: " + algorithm.name());
        }
        return KeyUtils.generateSymmetricKey(algorithm, keySize);
    }

    @Override
    public KeyPairInfo generateKeyPair(CryptoAlgorithm algorithm, int keySize) {
        if (!algorithm.isAsymmetric()) {
            throw new AlgorithmException("算法不是非对称加密算法: " + algorithm.name());
        }
        return KeyUtils.generateKeyPair(algorithm, keySize);
    }

    @Override
    public void registerEncryptStrategy(EncryptStrategy strategy) {
        encryptStrategies.put(strategy.algorithm(), strategy);
        log.info("注册加密策略: {}", strategy.algorithm().name());
    }

    @Override
    public void registerDecryptStrategy(DecryptStrategy strategy) {
        decryptStrategies.put(strategy.algorithm(), strategy);
        log.info("注册解密策略: {}", strategy.algorithm().name());
    }

    @Override
    public void setKeyStore(KeyStore keyStore) {
        if (keyStore == null) {
            throw new IllegalArgumentException("KeyStore cannot be null");
        }
        this.keyStore = keyStore;
        log.info("设置密钥存储实现: {}", keyStore.getClass().getSimpleName());
    }

    @Override
    public CryptoResult decryptWithStoredKey(String ciphertext, CryptoAlgorithm algorithm, String keyId) {
        try {
            if (keyId == null || keyId.trim().isEmpty()) {
                throw new CryptoException("密钥ID不能为空");
            }

            // 从存储中获取密钥上下文
            CryptoContext context = keyStore.retrieve(keyId);
            if (context == null) {
                throw new CryptoException("未找到密钥: " + keyId);
            }

            // 使用存储的密钥进行解密
            return decrypt(ciphertext, algorithm, context);
        } catch (Exception e) {
            log.error("使用存储密钥解密失败: keyId={}, error={}", keyId, e.getMessage(), e);
            return CryptoResult.failure(e.getMessage());
        }
    }
}

